home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP09.ZIP / CHAP09 / PATRON / TENANT.CPP < prev    next >
C/C++ Source or Header  |  1993-06-23  |  38KB  |  1,531 lines

  1. /*
  2.  * TENANT.CPP
  3.  * Modifications for Chapter 9
  4.  *
  5.  * Implementation of the CTentant class which holds information
  6.  * for a single object on a page.  It maintains position, references
  7.  * to data, and a storage.
  8.  *
  9.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Software Design Engineer
  12.  * Microsoft Systems Developer Relations
  13.  *
  14.  * Internet  :  kraigb@microsoft.com
  15.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  16.  */
  17.  
  18.  
  19. #include "patron.h"
  20.  
  21.  
  22. /*
  23.  * CTenant::CTenant
  24.  * CTenant::~CTenant
  25.  *
  26.  * Constructor Parameters:
  27.  *  dwID            DWORD identifier for this page.
  28.  *  hWnd            HWND of the pages window.
  29.  *  pPG             LPCPages to the parent structure.
  30.  */
  31.  
  32. CTenant::CTenant(DWORD dwID, HWND hWnd, LPCPages pPG)
  33.     {
  34.     m_hWnd=hWnd;
  35.     m_dwID=dwID;
  36.  
  37.     m_fInitialized=0;
  38.     m_pIStorage=NULL;
  39.     m_cOpens=0;
  40.  
  41.     m_pObj=NULL;
  42.     m_pPG =pPG;
  43.  
  44.     //CHAPTER9MOD
  45.     m_cRef=0;
  46.     m_pIOleObject=NULL;
  47.     m_pIViewObject=NULL;
  48.  
  49.     m_pIOleClientSite=NULL;
  50.     m_pIAdviseSink=NULL;
  51.     //End CHAPTER9MOD
  52.     return;
  53.     }
  54.  
  55.  
  56. CTenant::~CTenant(void)
  57.     {
  58.     //CHAPTER9MOD
  59.     if (NULL!=m_pIViewObject)
  60.         {
  61.         m_pIViewObject->SetAdvise(m_fe.dwAspect, 0, NULL);
  62.         m_pIViewObject->Release();
  63.         }
  64.  
  65.     if (NULL!=m_pIOleObject)
  66.         m_pIOleObject->Release();
  67.  
  68.     //We delete our own interfaces since we control them
  69.     if (NULL!=m_pIAdviseSink)
  70.         delete m_pIAdviseSink;
  71.  
  72.     if (NULL!=m_pIOleClientSite)
  73.         delete m_pIOleClientSite;
  74.     //End CHAPTER9MOD
  75.  
  76.     if (NULL!=m_pObj)
  77.         {
  78.         //We know we only hold one reference from UCreate or FLoad
  79.         m_pObj->Release();
  80.         m_pObj=NULL;
  81.         }
  82.  
  83.     return;
  84.     }
  85.  
  86.  
  87.  
  88.  
  89. //CHAPTER9MOD
  90. /*
  91.  * CTenant::QueryInterface
  92.  * CTenant::AddRef
  93.  * CTenant::Release
  94.  *
  95.  * Purpose:
  96.  *  IUnknown members for CTenant object.
  97.  */
  98.  
  99. STDMETHODIMP CTenant::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  100.     {
  101.     *ppv=NULL;
  102.  
  103.     //Any interface on this object is the object pointer.
  104.     if (IsEqualIID(riid, IID_IUnknown))
  105.         *ppv=(LPVOID)this;
  106.  
  107.     if (IsEqualIID(riid, IID_IOleClientSite))
  108.         *ppv=(LPVOID)m_pIOleClientSite;
  109.  
  110.     if (IsEqualIID(riid, IID_IAdviseSink))
  111.         *ppv=(LPVOID)m_pIAdviseSink;
  112.  
  113.     /*
  114.      * If we actually assign an interface to ppv we need to AddRef it
  115.      * since we're returning a new pointer.
  116.      */
  117.     if (NULL!=*ppv)
  118.         {
  119.         ((LPUNKNOWN)*ppv)->AddRef();
  120.         return NOERROR;
  121.         }
  122.  
  123.     return ResultFromScode(E_NOINTERFACE);
  124.     }
  125.  
  126.  
  127. STDMETHODIMP_(ULONG) CTenant::AddRef(void)
  128.     {
  129.     return ++m_cRef;
  130.     }
  131.  
  132. STDMETHODIMP_(ULONG) CTenant::Release(void)
  133.     {
  134.     ULONG           cRefT;
  135.  
  136.     cRefT=--m_cRef;
  137.  
  138.     if (0L==m_cRef)
  139.         delete this;
  140.  
  141.     return cRefT;
  142.     }
  143.  
  144. //End CHAPTER9MOD
  145.  
  146.  
  147.  
  148.  
  149.  
  150. /*
  151.  * CTenant::GetID
  152.  *
  153.  * Return Value:
  154.  *  DWORD           dwID field in this tenant.  This function is only here
  155.  *                  to avoid hiding inline implementations in pages.h
  156.  */
  157.  
  158. DWORD CTenant::GetID(void)
  159.     {
  160.     return m_dwID;
  161.     }
  162.  
  163.  
  164.  
  165.  
  166.  
  167. /*
  168.  * CTenant::GetStorageName
  169.  *
  170.  * Parameters:
  171.  *  pszName         LPSTR to a buffer in which to store the storage name
  172.  *                  for this tenant.
  173.  *
  174.  * Return Value:
  175.  *  UINT            Number of characters stored.
  176.  */
  177.  
  178. UINT CTenant::GetStorageName(LPSTR pszName)
  179.     {
  180.     return wsprintf(pszName, "Tenant %lu", m_dwID);
  181.     }
  182.  
  183.  
  184.  
  185.  
  186.  
  187. /*
  188.  * CTenant::UCreate
  189.  *
  190.  * Purpose:
  191.  *  Creates a new tenant of the given CLSID, which can be either a
  192.  *  static bitmap or metafile now (Chapter 7) and which may eventually
  193.  *  be any OLE object.
  194.  *
  195.  * Parameters:
  196.  *  tType           TENANTTYPE to create, either a static metafile, bitmap,
  197.  *                  or some kind of OLE object (later chapters)
  198.  *                  This determined which OleCreate* call we use.
  199.  *  pvType          LPVOID providing the relevant pointer from which
  200.  *                  to create the tenant, depending on iType.
  201.  *  pFE             LPFORMATETC specifying the type of renderings to use.
  202.  *  pptl            LPPOINTL in which we can store offset coordinates.
  203.  *  pszl            LPSIZEL where this object should store its lometric extents.
  204.  *  pIStorage       LPSTORAGE of the page we live in.  We have to
  205.  *                  create another storage under this for the tenant.
  206.  *  ppo             LPPATRONOBJECT containing placement data.
  207.  *  dwData          DWORD containing extra data, sensitive to iType.
  208.  *
  209.  * Return Value:
  210.  *  UINT            A UCREATE_* value depending on what we actually do.
  211.  */
  212.  
  213. UINT CTenant::UCreate(TENANTTYPE tType, LPVOID pvType, LPFORMATETC pFE
  214.     , LPPOINTL pptl, LPSIZEL pszl, LPSTORAGE pIStorage
  215.     , LPPATRONOBJECT ppo, DWORD dwData)
  216.     {
  217.     HRESULT             hr;
  218.     LPUNKNOWN           pObj;
  219.     UINT                uRet=UCREATE_GRAPHICONLY;
  220.  
  221.     if (NULL==pvType || NULL==pIStorage)
  222.         return UCREATE_FAILED;
  223.  
  224.     //Fail if this is called for an already living tenant.
  225.     if (m_fInitialized)
  226.         return UCREATE_FAILED;
  227.  
  228.     m_fInitialized=TRUE;
  229.  
  230.     //Create a new storage for this tenant.
  231.     if (!FOpen(pIStorage))
  232.         return UCREATE_FAILED;
  233.  
  234.     /*
  235.      * Get the placement info if it's here.  We either have a non-NULL
  236.      * LPPATRONOBJECT in ppo or we have to use default placement and
  237.      * retrieve the size from the object itself.
  238.      */
  239.     pszl->cx=0;
  240.     pszl->cy=0;
  241.  
  242.     if (NULL!=ppo)
  243.         {
  244.         *pFE=ppo->fe;
  245.         *pptl=ppo->ptl;
  246.         *pszl=ppo->szl;     //Could be 0,0 in which case we ask object
  247.  
  248.         uRet=UCREATE_PLACEDOBJECT;
  249.         }
  250.  
  251.     hr=ResultFromScode(E_FAIL);
  252.  
  253.     //Now create an object based specifically for the type.
  254.     switch (tType)
  255.         {
  256.         case TENANTTYPE_NULL:
  257.             break;
  258.  
  259.         case TENANTTYPE_STATIC:
  260.             /*
  261.              * We could use OleCreateStaticFromData here which does
  262.              * pretty much what we're doing below.  However, it does
  263.              * not allow us to control whether we paste a bitmap or
  264.              * a metafile--it uses metafile first, bitmap second.  For
  265.              * this reason we'll use code developed in Chapter 6's
  266.              * FreeLoader to affect the paste.
  267.              */
  268.             hr=CreateStatic((LPDATAOBJECT)pvType, pFE, &pObj);
  269.             break;
  270.  
  271.         //CHAPTER9MOD
  272.         case TENANTTYPE_EMBEDDEDOBJECT:
  273.             hr=OleCreate(*((LPCLSID)pvType), IID_IUnknown, OLERENDER_DRAW
  274.                 , NULL, NULL, m_pIStorage, (LPLPVOID)&pObj);
  275.             break;
  276.  
  277.         case TENANTTYPE_EMBEDDEDFILE:
  278.             hr=OleCreateFromFile(CLSID_NULL, (LPSTR)pvType, IID_IUnknown
  279.                 , OLERENDER_DRAW, NULL, NULL, m_pIStorage, (LPLPVOID)&pObj);
  280.             break;
  281.  
  282.         case TENANTTYPE_EMBEDDEDOBJECTFROMDATA:
  283.             hr=OleCreateFromData((LPDATAOBJECT)pvType, IID_IUnknown
  284.                 , OLERENDER_DRAW, NULL, NULL, m_pIStorage, (LPLPVOID)&pObj);
  285.             break;
  286.         //End CHAPTER9MOD
  287.  
  288.         default:
  289.             break;
  290.         }
  291.  
  292.     //If creation didn't work, get rid for the element FOpen created.
  293.     if (FAILED(hr))
  294.         {
  295.         Destroy(pIStorage);
  296.         return UCREATE_FAILED;
  297.         }
  298.  
  299.     //CHAPTER9MOD
  300.     //We don't get the size if PatronObject data was seen already.
  301.     FObjectInitialize(pObj, pFE, dwData);
  302.  
  303.     //We depend here on m_pIOleObject having been initialized.
  304.     if ((0==pszl->cx && 0==pszl->cy))
  305.         {
  306.         SIZEL   szl;
  307.  
  308.         //Try to get the real size of the object, default to 2"*2"
  309.         SETSIZEL((*pszl), 2*LOMETRIC_PER_INCH, 2*LOMETRIC_PER_INCH);
  310.  
  311.         if (SUCCEEDED(m_pIOleObject->GetExtent(pFE->dwAspect, &szl)))
  312.             {
  313.             /*
  314.              * Protect ourselves from OLE 1.0 servers that did MM_HIMETRIC
  315.              * instead of HIMETRIC units, thus had a negative y extent.
  316.              */
  317.             if (0 > szl.cy)
  318.                 szl.cy=-szl.cy;
  319.  
  320.             //Convert HIMETRIC to our LOMETRIC mapping, if meaningful
  321.             if (0!=szl.cx && 0!=szl.cy)
  322.                 SETSIZEL((*pszl), szl.cx/10, szl.cy/10);
  323.             }
  324.         }
  325.     //End CHAPTER9MOD
  326.  
  327.     return uRet;
  328.     }
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335. /*
  336.  * CTenant::FLoad
  337.  *
  338.  * Purpose:
  339.  *  Recreates the object living in this tenant in place of calling
  340.  *  FCreate.  This is used in loading as opposed to new creation.
  341.  *
  342.  * Parameters:
  343.  *  pIStorage       LPSTORAGE of the page we live in.
  344.  *  pFE             LPFORMATETC specifying the type of renderings to use.
  345.  *  prcl            LPRECTL where this object is positioned.
  346.  *
  347.  * Return Value:
  348.  *  BOOL            TRUE if successful, FALSE otherwise.
  349.  */
  350.  
  351. BOOL CTenant::FLoad(LPSTORAGE pIStorage, LPFORMATETC pFE, LPRECTL prcl)
  352.     {
  353.     HRESULT         hr;
  354.     LPUNKNOWN       pObj;
  355.  
  356.     if (NULL==pIStorage || NULL==pFE || NULL==prcl)
  357.         return FALSE;
  358.  
  359.     //Fail if this is called for an already living tenant.
  360.     if (m_fInitialized)
  361.         return FALSE;
  362.  
  363.     m_fInitialized=TRUE;
  364.  
  365.     //Open the storage for this tenant.
  366.     if (!FOpen(pIStorage))
  367.         return FALSE;
  368.  
  369.     hr=OleLoad(m_pIStorage, IID_IUnknown, NULL, (LPVOID FAR *)&pObj);
  370.  
  371.     if (FAILED(hr))
  372.         {
  373.         Destroy(pIStorage);
  374.         return FALSE;
  375.         }
  376.  
  377.     //CHAPTER9MOD
  378.     FObjectInitialize(pObj, pFE, NULL);
  379.     //End CHAPTER9MOD
  380.  
  381.     RectSet(prcl, FALSE);
  382.     return TRUE;
  383.     }
  384.  
  385.  
  386.  
  387.  
  388. //CHAPTER9MOD
  389. /*
  390.  * CTenant::FObjectInitialize
  391.  * (Protected)
  392.  *
  393.  * Purpose:
  394.  *  Performs operations necessary after creating an object or reloading
  395.  *  one from storage.
  396.  *
  397.  * Parameters:
  398.  *  pObj            LPUNKNOWN of the object in this tenant.
  399.  *  pFE             LPFORMATETC describing the graphic here.
  400.  *  dwData          DWORD extra data.  If pFE->dwAspect==DVASPECT_ICON
  401.  *                  then this is the iconic metafile.
  402.  *
  403.  * Return Value:
  404.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  405.  */
  406.  
  407. BOOL CTenant::FObjectInitialize(LPUNKNOWN pObj, LPFORMATETC pFE, DWORD dwData)
  408.     {
  409.     HRESULT         hr;
  410.     LPPERSIST       pIPersist=NULL;
  411.     DWORD           dw;
  412.     LPCDocument     pDoc;
  413.     char            szFile[CCHPATHMAX];
  414.  
  415.     if (NULL==pObj || NULL==pFE)
  416.         return FALSE;
  417.  
  418.     m_pObj=pObj;
  419.     m_fe=*pFE;
  420.     m_dwState=TENANTSTATE_DEFAULT;
  421.  
  422.     /*
  423.      * Determine the type:  Static or Embedded
  424.      * If Static, this will have CLSID_FreeMetafile or CLSID_FreeDib.
  425.      * Otherwise it's embedded.  Later we'll add a case for links.
  426.      */
  427.     m_tType=TENANTTYPE_EMBEDDEDOBJECT;
  428.  
  429.     if (SUCCEEDED(pObj->QueryInterface(IID_IPersist, (LPLPVOID)&pIPersist)))
  430.         {
  431.         CLSID   clsid;
  432.  
  433.         pIPersist->GetClassID(&clsid);
  434.  
  435.         if (IsEqualCLSID(clsid, CLSID_FreeMetafile)
  436.             || IsEqualCLSID(clsid, CLSID_FreeDib))
  437.             m_tType=TENANTTYPE_STATIC;
  438.  
  439.         pIPersist->Release();
  440.         }
  441.  
  442.  
  443.     m_pIViewObject=NULL;
  444.     hr=pObj->QueryInterface(IID_IViewObject, (LPLPVOID)&m_pIViewObject);
  445.  
  446.     if (FAILED(hr))
  447.         return FALSE;
  448.  
  449.     m_pIViewObject->SetAdvise(pFE->dwAspect, 0, m_pIAdviseSink);
  450.  
  451.     //We need an IOleObject most of the time, so get one here.
  452.     m_pIOleObject=NULL;
  453.     hr=pObj->QueryInterface(IID_IOleObject, (LPLPVOID)&m_pIOleObject);
  454.  
  455.     //Follow up object creation with advises and so forth.
  456.     if (FAILED(hr))
  457.         return FALSE;
  458.  
  459.     /*
  460.      * We could pass m_pIOleClientSite in an OleCreate* call, but
  461.      * since this function could be called after OleLoad, we still
  462.      * need to do this here, so it's always done here...
  463.      */
  464.     m_pIOleObject->SetClientSite(m_pIOleClientSite);
  465.     m_pIOleObject->Advise(m_pIAdviseSink, &dw);
  466.  
  467.     OleSetContainedObject((LPUNKNOWN)m_pIOleObject, TRUE);
  468.  
  469.     /*
  470.      * For IOleObject::SetHostNames we need the application name
  471.      * and the document name (which is passed in the object parameter).
  472.      * The design of Patron doesn't give us nice structured access to
  473.      * the name of the document we're in, so I grab the parent of
  474.      * the Pages window (the document) and send it DOCM_PDOCUMENT
  475.      * which returns us the pointer.  Roundabout, but it works.
  476.      */
  477.  
  478.     pDoc=(LPCDocument)SendMessage(GetParent(m_hWnd), DOCM_PDOCUMENT, 0, 0L);
  479.  
  480.     if (NULL!=pDoc)
  481.         pDoc->FilenameGet(szFile, CCHPATHMAX);
  482.     else
  483.         szFile[0]=0;
  484.  
  485.     NotifyOfRename(szFile, NULL);
  486.  
  487.     /*
  488.      * This might have been Display as Icon if pFE->dwAspect=DVASPECT_ICON.
  489.      * If so, then dwData is a handle to a metafile with the iconic
  490.      * aspect.  We take this and shove it into the cache for this
  491.      * aspect, releasing the content aspect.  OLE2UI has a nice function
  492.      * that does this:  OleStdSwitchDisplayAspect, which also handles a
  493.      * later case (Chapter 14) when we might want to switch BACK to content.
  494.      * That, however, requires the Change Type dialog.
  495.      */
  496.  
  497.     if ((DVASPECT_ICON & pFE->dwAspect) && NULL!=dwData)
  498.         {
  499.         //Temps to give to OleStdSwitchDisplayAspect
  500.         DWORD       dw=DVASPECT_CONTENT;
  501.         BOOL        fUpdate;
  502.  
  503.         OleStdSwitchDisplayAspect(m_pIOleObject, &dw, DVASPECT_ICON
  504.             , (HGLOBAL)(UINT)dwData, TRUE, FALSE, NULL, &fUpdate);
  505.         }
  506.  
  507.     return TRUE;
  508.     }
  509. //End CHAPTER9MOD
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516. /*
  517.  * CTenant::FOpen
  518.  *
  519.  * Purpose:
  520.  *  Retrieves the IStorage associated with this tenant.  The IStorage is
  521.  *  owned by the tenant and thus the tenant always holds a reference count.
  522.  *
  523.  *  If the storage is already open for this tenant, then this function will
  524.  *  AddRef it; therefore the caller must always match an FOpen with a Close.
  525.  *
  526.  * Parameters:
  527.  *  pIStorage       LPSTORAGE above this tenant (which has its own storage).
  528.  *
  529.  * Return Value:
  530.  *  BOOL            TRUE if opening succeeds, FALSE otherwise.
  531.  */
  532.  
  533. BOOL CTenant::FOpen(LPSTORAGE pIStorage)
  534.     {
  535.     HRESULT     hr=NOERROR;
  536.     DWORD       dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  537.     char        szTemp[32];
  538.  
  539.     if (NULL==m_pIStorage)
  540.         {
  541.         if (NULL==pIStorage)
  542.             return FALSE;
  543.  
  544.         /*
  545.          * Attempt to open the storage under this ID.  If there is none, then
  546.          * create it.  In either case we end up with an IStorage that we
  547.          * either save in pPage or release.
  548.          */
  549.  
  550.         GetStorageName(szTemp);
  551.         hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0, &m_pIStorage);
  552.  
  553.         if (FAILED(hr))
  554.             hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0, &m_pIStorage);
  555.         }
  556.     else
  557.         m_pIStorage->AddRef();
  558.  
  559.     if (FAILED(hr))
  560.         return FALSE;
  561.  
  562.     m_cOpens++;
  563.  
  564.     //CHAPTER9MOD
  565.     m_pIOleClientSite=new CImpIOleClientSite(this, (LPUNKNOWN)this);
  566.     m_pIAdviseSink=new CImpIAdviseSink(this, (LPUNKNOWN)this);
  567.  
  568.     if (NULL==m_pIOleClientSite || NULL==m_pIAdviseSink)
  569.         return FALSE;
  570.     //End CHAPTER9MOD
  571.  
  572.     return TRUE;
  573.     }
  574.  
  575.  
  576.  
  577.  
  578. /*
  579.  * CTenant::Close
  580.  *
  581.  * Purpose:
  582.  *  Possibly commits the storage, then releases it reversing the
  583.  *  reference count from FOpen.  If the reference on the storage
  584.  *  goes to zero, the storage is forgotten.  However, the object we
  585.  *  contain is still held and as long as it's active the storage
  586.  *  remains alive.
  587.  *
  588.  * Parameters:
  589.  *  fCommit         BOOL indicating if we're to commit.
  590.  *
  591.  * Return Value:
  592.  *  None
  593.  */
  594.  
  595. void CTenant::Close(BOOL fCommit)
  596.     {
  597.     if (fCommit)
  598.         Update();
  599.  
  600.     if (NULL!=m_pIStorage)
  601.         {
  602.         m_pIStorage->Release();
  603.  
  604.         /*
  605.          * We can't use a zero reference count to know when to NULL
  606.          * this since other things might have AddRef'd the storage.
  607.          */
  608.         //CHAPTER9MOD
  609.         if (0==--m_cOpens)
  610.             {
  611.             m_pIStorage=NULL;
  612.  
  613.             //Close the object saving if necessary
  614.             if (NULL!=m_pIOleObject)
  615.                 m_pIOleObject->Close(OLECLOSE_SAVEIFDIRTY);
  616.             }
  617.         //End CHAPTER9MOD
  618.         }
  619.  
  620.     return;
  621.     }
  622.  
  623.  
  624.  
  625.  
  626. /*
  627.  * CTenant::Update
  628.  *
  629.  * Purpose:
  630.  *  Forces a common on the page if it's open.
  631.  *
  632.  * Parameters:
  633.  *  None
  634.  *
  635.  * Return Value:
  636.  *  BOOL            TRUE if the object is open, FALSE otherwise.
  637.  */
  638.  
  639. BOOL CTenant::Update(void)
  640.     {
  641.     LPPERSISTSTORAGE    pIPS;
  642.  
  643.     if (NULL!=m_pIStorage)
  644.         {
  645.         /*
  646.          * We need to OleSave again because we might have changed the
  647.          * size or position of this tenant.  We also need to save the
  648.          * rectangle on the page, since that's not known to OLE.
  649.          */
  650.         m_pObj->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&pIPS);
  651.         OleSave(pIPS, m_pIStorage, TRUE);
  652.         pIPS->SaveCompleted(NULL);
  653.         pIPS->Release();
  654.  
  655.         m_pIStorage->Commit(STGC_ONLYIFCURRENT);
  656.         }
  657.  
  658.     return FALSE;
  659.     }
  660.  
  661.  
  662.  
  663.  
  664.  
  665. /*
  666.  * CTenant::Destroy
  667.  *
  668.  * Purpose:
  669.  *  Removes this page from the given storage.  The caller should
  670.  *  eventually delete this CTenant object to free the object herein.
  671.  *  Nothing is committed when being destroyed.
  672.  *
  673.  * Parameters:
  674.  *  pIStorage       LPSTORAGE contianing this page on which to call
  675.  *                  ::DestroyElement
  676.  *
  677.  * Return Value:
  678.  *  None
  679.  */
  680.  
  681. void CTenant::Destroy(LPSTORAGE pIStorage)
  682.     {
  683.     char        szTemp[32];
  684.  
  685.     if (NULL!=pIStorage)
  686.         {
  687.         //CHAPTER9MOD
  688.         if (NULL!=m_pIOleObject)
  689.             m_pIOleObject->Close(OLECLOSE_NOSAVE);
  690.         //End CHAPTER9MOD
  691.  
  692.         if (NULL!=m_pIStorage)
  693.             {
  694.             //Remove all reference/open counts on this storage.
  695.             while (0!=m_cOpens)
  696.                 {
  697.                 m_pIStorage->Release();
  698.                 m_cOpens--;
  699.                 }
  700.             }
  701.  
  702.         GetStorageName(szTemp);
  703.         pIStorage->DestroyElement(szTemp);
  704.  
  705.         m_pIStorage=NULL;
  706.         }
  707.  
  708.     //m_pObj is released in destructor.
  709.     return;
  710.     }
  711.  
  712.  
  713.  
  714.  
  715. /*
  716.  * CTenant::Select
  717.  *
  718.  * Purpose:
  719.  *  Selects or deselects the tenant.
  720.  *
  721.  * Parameters:
  722.  *  fSelect         BOOL indicating the new state of the tenant.
  723.  *
  724.  * Return Value:
  725.  *  None
  726.  */
  727.  
  728. void CTenant::Select(BOOL fSelect)
  729.     {
  730.     BOOL        fWasSelected;
  731.     DWORD       dwState;
  732.     RECT        rc;
  733.     HDC         hDC;
  734.  
  735.     fWasSelected=(BOOL)(TENANTSTATE_SELECTED & m_dwState);
  736.  
  737.     //Nothing to do when there's no change.
  738.     if (fWasSelected==fSelect)
  739.         return;
  740.  
  741.     dwState=m_dwState & ~TENANTSTATE_SELECTED;
  742.     m_dwState=dwState | ((fSelect) ? TENANTSTATE_SELECTED : 0);
  743.  
  744.     /*
  745.      * Draw sizing handles to show the selection state.  We convert
  746.      * things to MM_TEXT since that's what this function expects.
  747.      */
  748.  
  749.     RECTFROMRECTL(rc, m_rcl);
  750.     RectConvertMappings(&rc, NULL, TRUE);
  751.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  752.  
  753.     hDC=GetDC(m_hWnd);
  754.  
  755.     OleUIDrawHandles(&rc, hDC, OLEUI_HANDLES_INSIDE | OLEUI_HANDLES_NOBORDER
  756.         | OLEUI_HANDLES_USEINVERSE, CXYHANDLE, !fWasSelected);
  757.  
  758.     ReleaseDC(m_hWnd, hDC);
  759.     return;
  760.     }
  761.  
  762.  
  763.  
  764.  
  765. //CHAPTER9MOD
  766. /*
  767.  * CTenant::ShowAsOpen
  768.  *
  769.  * Purpose:
  770.  *  Draws or removes the hatch pattern over an object.
  771.  *
  772.  * Parameters:
  773.  *  fOpen           BOOL indicating the open state of this tenant.
  774.  *
  775.  * Return Value:
  776.  *  None
  777.  */
  778.  
  779. void CTenant::ShowAsOpen(BOOL fOpen)
  780.     {
  781.     BOOL        fWasOpen;
  782.     DWORD       dwState;
  783.     RECT        rc;
  784.     HDC         hDC;
  785.  
  786.     fWasOpen=(BOOL)(TENANTSTATE_OPEN & m_dwState);
  787.  
  788.     dwState=m_dwState & ~TENANTSTATE_OPEN;
  789.     m_dwState=dwState | ((fOpen) ? TENANTSTATE_OPEN : 0);
  790.  
  791.     //If this was not open, then just hatch, otherwise repaint.
  792.     if (!fWasOpen && fOpen)
  793.         {
  794.         RECTFROMRECTL(rc, m_rcl);
  795.         RectConvertMappings(&rc, NULL, TRUE);
  796.         OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  797.  
  798.         hDC=GetDC(m_hWnd);
  799.         OleUIDrawShading(&rc, hDC, OLEUI_SHADE_FULLRECT, 0);
  800.         ReleaseDC(m_hWnd, hDC);
  801.         }
  802.  
  803.     if (fWasOpen && !fOpen)
  804.         Repaint();
  805.  
  806.     return;
  807.     }
  808.  
  809.  
  810.  
  811.  
  812.  
  813. /*
  814.  * CTenant::ShowYourself
  815.  *
  816.  * Purpose:
  817.  *  Function that really just implements IOleClientSite::ShowObject.
  818.  *  Here we first check if the tenant is fully visible, and if so, then
  819.  *  nothing needs to happen.  Otherwise, if the upper left corner of
  820.  *  the tenant is in the upper left visible quadrant of the window, we'll
  821.  *  also consider ourselves done.  Otherwise we'll put the upper left
  822.  *  corner of the object at the upper left corner of the window.
  823.  *
  824.  * Parameters:
  825.  *  None
  826.  *
  827.  * Return Value:
  828.  *  None
  829.  */
  830.  
  831. void CTenant::ShowYourself(void)
  832.     {
  833.     RECTL       rcl;
  834.     RECT        rc;
  835.     POINT       pt1, pt2;
  836.  
  837.     //Scrolling deals in device units, so get our rectangle in those.
  838.     RectGet(&rcl, TRUE);
  839.  
  840.     //Get the window rectangle offset for the current scroll position.
  841.     GetClientRect(m_hWnd, &rc);
  842.     OffsetRect(&rc, m_pPG->m_xPos, m_pPG->m_yPos);
  843.  
  844.     //Check if the object is already visible. (macro in bookguid.h)
  845.     SETPOINT(pt1, (int)rcl.left,  (int)rcl.top);
  846.     SETPOINT(pt2, (int)rcl.right, (int)rcl.bottom);
  847.  
  848.     if (PtInRect(&rc, pt1) && PtInRect(&rc, pt2))
  849.         return;
  850.  
  851.     //Check if the upper left is within the upper left quadrant
  852.     if (((int)rcl.left > rc.left && (int)rcl.left < ((rc.right+rc.left)/2))
  853.         && ((int)rcl.top > rc.top && (int)rcl.top < ((rc.bottom+rc.top)/2)))
  854.         return;
  855.  
  856.     //These are macros in INC\WIN1632.H
  857.     SendScrollPosition(m_hWnd, WM_HSCROLL, rcl.left-8);
  858.     SendScrollPosition(m_hWnd, WM_VSCROLL, rcl.top-8);
  859.     return;
  860.     }
  861.  
  862.  
  863.  
  864. /*
  865.  * CTenant::AddVerbMenu
  866.  *
  867.  * Purpose:
  868.  *  Creates the variable verb menu item for the object in this tenant.
  869.  *
  870.  * Parmeters:
  871.  *  hMenu           HMENU on which to add items.
  872.  *  iPos            UINT position on that menu to add items.
  873.  *
  874.  * Return Value:
  875.  *  None
  876.  */
  877.  
  878. void CTenant::AddVerbMenu(HMENU hMenu, UINT iPos)
  879.     {
  880.     HMENU       hMenuTemp;
  881.     LPOLEOBJECT pObj=m_pIOleObject;
  882.  
  883.     //If we're static, say we have no object.
  884.     if (TENANTTYPE_STATIC==m_tType)
  885.         pObj=NULL;
  886.  
  887.     OleUIAddVerbMenu(pObj, NULL, hMenu, iPos, IDM_VERBMIN
  888.         , FALSE, 0, &hMenuTemp);
  889.  
  890.     return;
  891.     }
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898. /*
  899.  * CTenant::CopyEmbeddedObject
  900.  *
  901.  * Purpose:
  902.  *  Copies an embedded object to the given data object (via SetData, assuming
  903.  *  this is a data transfer object for clipboard/drag-drop) if that's what
  904.  *  we're holding.
  905.  *
  906.  * Parameters:
  907.  *  pIDataObject    LPDATAOBJECT in which to store the copy.
  908.  *  pFE             LPFORMATETC into which to copy CF_EMBEDDEDOBJECT
  909.  *                  if we put that in the data object.
  910.  *  pptl            LPPOINTL to the pick point (NULL outside of drag-drop);
  911.  *
  912.  * Return Value:
  913.  *  None
  914.  */
  915.  
  916. void CTenant::CopyEmbeddedObject(LPDATAOBJECT pIDataObject, LPFORMATETC pFE
  917.     , LPPOINTL pptl)
  918.     {
  919.     LPPERSISTSTORAGE    pIPS;
  920.     STGMEDIUM           stm;
  921.     FORMATETC           fe;
  922.     HRESULT             hr;
  923.     UINT                cf;
  924.     POINTL              ptl;
  925.  
  926.     //Can only copy embeddings.
  927.     if (TENANTTYPE_EMBEDDEDOBJECT!=m_tType)
  928.         return;
  929.  
  930.     if (NULL==pptl)
  931.         {
  932.         SETPOINTL(ptl, 0, 0);
  933.         pptl=&ptl;
  934.         }
  935.  
  936.     /*
  937.      * Create CF_EMBEDDEDOBJECT.  This is simply an IStorage with a
  938.      * copy of the embedded object in it.  The not-so-simple part is
  939.      * getting an IStorage to stuff it in.  For this operation we'll
  940.      * use a temporary compound file.
  941.      */
  942.  
  943.     stm.tymed=TYMED_ISTORAGE;
  944.     hr=StgCreateDocfile(NULL, STGM_TRANSACTED | STGM_READWRITE | STGM_CREATE
  945.         | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &stm.pstg);
  946.  
  947.     if (FAILED(hr))
  948.         return;
  949.  
  950.     m_pObj->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&pIPS);
  951.  
  952.     if (NOERROR==pIPS->IsDirty())
  953.         {
  954.         OleSave(pIPS, stm.pstg, FALSE);
  955.         pIPS->SaveCompleted(NULL);
  956.         }
  957.     else
  958.         m_pIStorage->CopyTo(0, NULL, NULL, stm.pstg);
  959.  
  960.     pIPS->Release();
  961.  
  962.     //stm.pstg now has a copy, so stuff it away.
  963.     cf=RegisterClipboardFormat(CF_EMBEDDEDOBJECT);
  964.     SETDefFormatEtc(fe, cf, TYMED_ISTORAGE);
  965.  
  966.     if (SUCCEEDED(pIDataObject->SetData(&fe, &stm, TRUE)))
  967.         *pFE=fe;
  968.     else
  969.         ReleaseStgMedium(&stm);
  970.  
  971.     //Create CF_OBJECTDESCRIPTOR which OLE2UI handles.
  972.     stm.tymed=TYMED_HGLOBAL;
  973.  
  974.     /*
  975.      * You want to make sure that if this object is iconic, that you
  976.      * create the object descriptor with DVASPECT_ICON instead of
  977.      * the more typical DVASPECT_CONTENT.  Also remember that
  978.      * the pick point is in HIMETRIC.
  979.      */
  980.     XformSizeInPixelsToHimetric(NULL, (LPSIZEL)pptl, (LPSIZEL)&ptl);
  981.     stm.hGlobal=OleStdGetObjectDescriptorDataFromOleObject(m_pIOleObject
  982.         , NULL, m_fe.dwAspect, ptl);
  983.  
  984.     cf=RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);
  985.     SETDefFormatEtc(fe, cf, TYMED_HGLOBAL);
  986.  
  987.     if (FAILED(pIDataObject->SetData(&fe, &stm, TRUE)))
  988.         ReleaseStgMedium(&stm);
  989.  
  990.     return;
  991.     }
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999. /*
  1000.  * CTenant::NotifyOfRename
  1001.  *
  1002.  * Purpose:
  1003.  *  Instructs the tenant that the document was saved under a different
  1004.  *  name.  In order to keep the right compound document user interface,
  1005.  *  this tenant needs to tell its object through IOleObject::SetHostNames.
  1006.  *
  1007.  * Parameters:
  1008.  *  pszFile         LPSTR of filename.
  1009.  *  pvReserved      LPVOID reserved for future use.
  1010.  *
  1011.  * Return Value:
  1012.  *  None
  1013.  */
  1014.  
  1015. void CTenant::NotifyOfRename(LPSTR pszFile, LPVOID pvReserved)
  1016.     {
  1017.     char        szObj[40];
  1018.     char        szApp[40];
  1019.  
  1020.     if (NULL==m_pIOleObject)
  1021.         return;
  1022.  
  1023.     if (0==*pszFile)
  1024.         LoadString(m_pPG->m_hInst, IDS_UNTITLED, szObj, sizeof(szObj));
  1025.     else
  1026.         {
  1027.         GetFileTitle(pszFile, szObj, sizeof(szObj));
  1028.  
  1029.        #ifndef WIN32
  1030.         //Force filenames to uppercase in DOS versions.
  1031.         AnsiUpper(szObj);
  1032.        #endif
  1033.         }
  1034.  
  1035.     LoadString(m_pPG->m_hInst, IDS_CAPTION, szApp, sizeof(szApp));
  1036.     m_pIOleObject->SetHostNames(szApp, szObj);
  1037.     return;
  1038.     }
  1039.  
  1040. //End CHAPTER9MOD
  1041.  
  1042.  
  1043.  
  1044.  
  1045.  
  1046.  
  1047.  
  1048.  
  1049. /*
  1050.  * CTenant::Activate
  1051.  *
  1052.  * Purpose:
  1053.  *  Activates a verb on the object living in the tenant.  Does nothing
  1054.  *  for static objects.
  1055.  *
  1056.  * Parameters:
  1057.  *  iVerb           DWORD of the verb to execute.
  1058.  *
  1059.  * Return Value:
  1060.  *  BOOL            TRUE if the object changed due to this verb execution.
  1061.  */
  1062.  
  1063. BOOL CTenant::Activate(DWORD iVerb)
  1064.     {
  1065.     //CHAPTER9MOD
  1066.     RECT        rc, rcH;
  1067.     HCURSOR     hCur;
  1068.  
  1069.     //Can't activate statics.
  1070.     if (TENANTTYPE_STATIC==m_tType)
  1071.         {
  1072.         MessageBeep(0);
  1073.         return FALSE;
  1074.         }
  1075.  
  1076.     RECTFROMRECTL(rc, m_rcl);
  1077.     RectConvertMappings(&rc, NULL, TRUE);
  1078.     XformRectInPixelsToHimetric(NULL, &rc, &rcH);
  1079.  
  1080.     hCur=SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)));
  1081.     ShowCursor(TRUE);
  1082.  
  1083.     m_pIOleObject->DoVerb(iVerb, NULL, m_pIOleClientSite, 0, m_hWnd, &rcH);
  1084.  
  1085.     SetCursor(hCur);
  1086.     ShowCursor(FALSE);
  1087.  
  1088.     //If the object does change, IAdviseSink::OnViewChange will see it.
  1089.     return FALSE;
  1090.     //End CHAPTER9MOD
  1091.     }
  1092.  
  1093.  
  1094.  
  1095.  
  1096.  
  1097.  
  1098. /*
  1099.  * CTenant::Draw
  1100.  *
  1101.  * Purpose:
  1102.  *  Draws the tenant in its rectangle on the given hDC.  We assume the
  1103.  *  DC is already set up for the mapping mode in which our rectangle
  1104.  *  is expressed, since the Page we're in tells us both the rect and
  1105.  *  the hDC.
  1106.  *
  1107.  * Parameters:
  1108.  *  hDC             HDC in which to draw.  Could be a metafile, memory
  1109.  *                  DC, screen, or printer.  We simply don't know.
  1110.  *  ptd             DVTARGETDEVICE FAR * describing the device.
  1111.  *  hIC             HDC holding an information context (printing).
  1112.  *  xOff, yOff      int offsets for the page in lometric
  1113.  *  fNoColor        BOOL indicating if we should do B & W
  1114.  *  fPrinter        BOOL indicating if we should render for a printer.
  1115.  *
  1116.  * Return Value:
  1117.  *  None
  1118.  */
  1119.  
  1120. void CTenant::Draw(HDC hDC, DVTARGETDEVICE FAR *ptd, HDC hIC, int xOff
  1121.     , int yOff, BOOL fNoColor, BOOL fPrinter)
  1122.     {
  1123.     HRESULT         hr;
  1124.     RECT            rc;
  1125.     RECTL           rcl;
  1126.     UINT            uMM;
  1127.  
  1128.     //CHAPTER9MOD
  1129.     //We hold IViewObject all the time now, so no need for QueryInterface
  1130.     //End CHAPTER9MOD
  1131.  
  1132.     RECTFROMRECTL(rc, m_rcl);
  1133.     OffsetRect(&rc, -xOff, -yOff);
  1134.     RECTLFROMRECT(rcl, rc);
  1135.  
  1136.     //CHAPTER9MOD
  1137.     //Repaint needs to erase the rectangle to insure full object cleanup
  1138.     if (!fNoColor && !fPrinter)
  1139.         {
  1140.         COLORREF    cr;
  1141.         cr=SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  1142.         ExtTextOut(hDC, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 0, NULL);
  1143.         SetBkColor(hDC, cr);
  1144.         }
  1145.  
  1146.     //We have to use Draw since we have a target device and IC.
  1147.     hr=m_pIViewObject->Draw(m_fe.dwAspect, -1, NULL, ptd, hIC, hDC
  1148.         , &rcl, NULL, NULL, 0);
  1149.  
  1150.     //End CHAPTER9MOD
  1151.  
  1152.     /*
  1153.      * If Draw failed, then perhaps it couldn't work for the device,
  1154.      * so try good old OleDraw as a last resort.  The code will
  1155.      * generally be OLE_E_BLANK.
  1156.      */
  1157.     if (FAILED(hr))
  1158.         OleDraw(m_pObj, m_fe.dwAspect, hDC, &rc);
  1159.  
  1160.     //CHAPTER9MOD
  1161.     if (!fPrinter && (TENANTSTATE_SELECTED | TENANTSTATE_OPEN) & m_dwState)
  1162.         {
  1163.         /*
  1164.          * Draw sizing handles to show the selection state.  We convert
  1165.          * things to MM_TEXT since that's what this function expects.
  1166.          */
  1167.         RectConvertMappings(&rc, NULL, TRUE);
  1168.         uMM=SetMapMode(hDC, MM_TEXT);
  1169.  
  1170.         if (TENANTSTATE_SELECTED & m_dwState)
  1171.             {
  1172.             OleUIDrawHandles(&rc, hDC, OLEUI_HANDLES_INSIDE
  1173.                 | OLEUI_HANDLES_NOBORDER | OLEUI_HANDLES_USEINVERSE
  1174.                 , CXYHANDLE, TRUE);
  1175.             }
  1176.  
  1177.         if (TENANTSTATE_OPEN & m_dwState)
  1178.             OleUIDrawShading(&rc, hDC, OLEUI_SHADE_FULLRECT, 0);
  1179.  
  1180.         uMM=SetMapMode(hDC, uMM);
  1181.         }
  1182.     //End CHAPTER9MOD
  1183.  
  1184.     return;
  1185.     }
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191. /*
  1192.  * CTenant::Repaint
  1193.  * CTenant::Invalidate
  1194.  *
  1195.  * Purpose:
  1196.  *  Repaints the tenant where it lies or invalidates its area
  1197.  *  for later repainting.
  1198.  *
  1199.  * Parameters:
  1200.  *  None
  1201.  *
  1202.  * Return Value:
  1203.  *  None
  1204.  */
  1205.  
  1206. void CTenant::Repaint(void)
  1207.     {
  1208.     RECT        rc;
  1209.     HDC         hDC;
  1210.  
  1211.     //CHAPTER9MOD
  1212.     /*
  1213.      * We might be asked to repaint from IOleClientSite::OnShowWindow
  1214.      * after we've switched pages if our server was runnnig.  This check
  1215.      * on m_cOpens prevents that.
  1216.      */
  1217.     if (0==m_cOpens)
  1218.         return;
  1219.     //End CHAPTER9MOD
  1220.  
  1221.     hDC=GetDC(m_hWnd);
  1222.     SetRect(&rc, m_pPG->m_xPos, m_pPG->m_yPos, 0, 0);
  1223.     RectConvertMappings(&rc, NULL, FALSE);
  1224.  
  1225.     SetMapMode(hDC, MM_LOMETRIC);
  1226.     Draw(hDC, NULL, NULL, rc.left, rc.top, FALSE, FALSE);
  1227.  
  1228.     ReleaseDC(m_hWnd, hDC);
  1229.     return;
  1230.     }
  1231.  
  1232.  
  1233. void CTenant::Invalidate(void)
  1234.     {
  1235.     RECTL       rcl;
  1236.     RECT        rc;
  1237.  
  1238.     RectGet(&rcl, TRUE);
  1239.     RECTFROMRECTL(rc, rcl);
  1240.  
  1241.     OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  1242.     InvalidateRect(m_hWnd, &rc, FALSE);
  1243.  
  1244.     return;
  1245.     }
  1246.  
  1247.  
  1248.  
  1249.  
  1250.  
  1251.  
  1252. /*
  1253.  * CTenant::ObjectGet
  1254.  *
  1255.  * Purpose:
  1256.  *  Retrieves the LPUNKNOWN of the object in use by this tenant
  1257.  *
  1258.  * Parameters:
  1259.  *  ppUnk           LPUNKNOWN FAR * in which to return the object pointer.
  1260.  *
  1261.  * Return Value:
  1262.  *  None
  1263.  */
  1264.  
  1265. void CTenant::ObjectGet(LPUNKNOWN FAR *ppUnk)
  1266.     {
  1267.     if (NULL!=ppUnk)
  1268.         {
  1269.         *ppUnk=m_pObj;
  1270.         m_pObj->AddRef();
  1271.         }
  1272.  
  1273.     return;
  1274.     }
  1275.  
  1276.  
  1277.  
  1278.  
  1279.  
  1280. /*
  1281.  * CTenant::FormatEtcGet
  1282.  *
  1283.  * Purpose:
  1284.  *  Retrieves the FORMATETC in use by this tenant
  1285.  *
  1286.  * Parameters:
  1287.  *  pFE             LPFORMATETC in which to store the information.
  1288.  *  fPresentation   BOOL indicating if we want the real format or that
  1289.  *                  of the presentation.
  1290.  *
  1291.  * Return Value:
  1292.  *  None
  1293.  */
  1294.  
  1295. void CTenant::FormatEtcGet(LPFORMATETC pFE, BOOL fPresentation)
  1296.     {
  1297.     if (NULL!=pFE)
  1298.         {
  1299.         *pFE=m_fe;
  1300.  
  1301.         //CHAPTER9MOD
  1302.         //If there is no format, use metafile (for embedded objects)
  1303.         if (fPresentation || 0==pFE->cfFormat)
  1304.             {
  1305.             //Don't mess with dwAspect since it might be icon or content.
  1306.             pFE->cfFormat=CF_METAFILEPICT;
  1307.             pFE->tymed=TYMED_MFPICT;
  1308.             }
  1309.         //End CHAPTER9MOD
  1310.         }
  1311.  
  1312.     return;
  1313.     }
  1314.  
  1315.  
  1316.  
  1317.  
  1318.  
  1319. /*
  1320.  * CTenant::SizeGet
  1321.  * CTenant::SizeSet
  1322.  * CTenant::RectGet
  1323.  * CTenant::RectSet
  1324.  *
  1325.  * Purpose:
  1326.  *  Returns or sets the size/position of the object contained here.
  1327.  *
  1328.  * Parameters:
  1329.  *  pszl/prcl       LPSIZEL (Size) or LPRECTL (Rect) with the extents of
  1330.  *                  interest.  In Get situations, this will receive the
  1331.  *                  extents; in Set it contains the extents.
  1332.  *  fDevice         BOOL indicating that pszl/prcl is expressed in device
  1333.  *                  units.  Otherwise it's LOMETRIC.
  1334.  *
  1335.  * Return Value:
  1336.  *  None
  1337.  */
  1338.  
  1339. void CTenant::SizeGet(LPSIZEL pszl, BOOL fDevice)
  1340.     {
  1341.     if (!fDevice)
  1342.         {
  1343.         pszl->cx=m_rcl.right-m_rcl.left;
  1344.         pszl->cy=m_rcl.bottom-m_rcl.top;
  1345.         }
  1346.     else
  1347.         {
  1348.         RECT        rc;
  1349.  
  1350.         SetRect(&rc, (int)(m_rcl.right-m_rcl.left)
  1351.             , (int)(m_rcl.bottom-m_rcl.top), 0, 0);
  1352.  
  1353.         RectConvertMappings(&rc, NULL, TRUE);
  1354.  
  1355.         pszl->cx=(long)rc.left;
  1356.         pszl->cy=(long)rc.top;
  1357.         }
  1358.  
  1359.     return;
  1360.     }
  1361.  
  1362.  
  1363. void CTenant::SizeSet(LPSIZEL pszl, BOOL fDevice)
  1364.     {
  1365.     SIZEL           szl;
  1366.  
  1367.     if (!fDevice)
  1368.         {
  1369.         szl=*pszl;
  1370.         m_rcl.right =pszl->cx+m_rcl.left;
  1371.         m_rcl.bottom=pszl->cy+m_rcl.top;
  1372.         }
  1373.     else
  1374.         {
  1375.         RECT        rc;
  1376.  
  1377.         SetRect(&rc, (int)pszl->cx, (int)pszl->cy, 0, 0);
  1378.         RectConvertMappings(&rc, NULL, FALSE);
  1379.  
  1380.         m_rcl.right =(long)rc.left+m_rcl.left;
  1381.         m_rcl.bottom=(long)rc.top+m_rcl.top;
  1382.  
  1383.         SETSIZEL(szl, (long)rc.left, (long)rc.top);
  1384.         }
  1385.  
  1386.  
  1387.     //Tell OLE that this object was resized.
  1388.     if (NULL!=m_pObj)
  1389.         {
  1390.         HRESULT     hr;
  1391.         LPOLEOBJECT pIOleObject;
  1392.  
  1393.         hr=m_pObj->QueryInterface(IID_IOleObject, (LPVOID FAR *)&pIOleObject);
  1394.  
  1395.         if (SUCCEEDED(hr))
  1396.             {
  1397.             //Convert our LOMETRIC into HIMETRIC by *=10
  1398.             szl.cx*=10;
  1399.             szl.cy*=-10;    //Our size is stored negative.
  1400.  
  1401.             pIOleObject->SetExtent(m_fe.dwAspect, &szl);
  1402.             pIOleObject->Release();
  1403.             }
  1404.         }
  1405.  
  1406.     return;
  1407.     }
  1408.  
  1409.  
  1410. void CTenant::RectGet(LPRECTL prcl, BOOL fDevice)
  1411.     {
  1412.     if (!fDevice)
  1413.         *prcl=m_rcl;
  1414.     else
  1415.         {
  1416.         RECT        rc;
  1417.  
  1418.         RECTFROMRECTL(rc, m_rcl);
  1419.         RectConvertMappings(&rc, NULL, TRUE);
  1420.         RECTLFROMRECT(*prcl, rc);
  1421.         }
  1422.  
  1423.     return;
  1424.     }
  1425.  
  1426.  
  1427. void CTenant::RectSet(LPRECTL prcl, BOOL fDevice)
  1428.     {
  1429.     SIZEL   szl;
  1430.  
  1431.     if (!fDevice)
  1432.         m_rcl=*prcl;
  1433.     else
  1434.         {
  1435.         RECT        rc;
  1436.  
  1437.         RECTFROMRECTL(rc, *prcl);
  1438.         RectConvertMappings(&rc, NULL, FALSE);
  1439.         RECTLFROMRECT(m_rcl, rc);
  1440.         }
  1441.  
  1442.     //Tell ourselves that the size changes.
  1443.     SETSIZEL(szl, m_rcl.right-m_rcl.left, m_rcl.bottom-m_rcl.top);
  1444.     SizeSet(&szl, FALSE);
  1445.  
  1446.     return;
  1447.     }
  1448.  
  1449.  
  1450.  
  1451.  
  1452.  
  1453.  
  1454.  
  1455. /*
  1456.  * CTenant::CreateStatic
  1457.  * (Protected)
  1458.  *
  1459.  * Purpose:
  1460.  *  Creates a new static bitmap or metafile object for this tenant
  1461.  *  using a freeloading method allowing us to specify exactly which
  1462.  *  type of data we want to paste since OleCreateStaticFromData doesn't.
  1463.  *
  1464.  * Parameters:
  1465.  *  pIDataObject    LPDATAOBJECT from which to paste.
  1466.  *  pFE             LPFORMATETC describing the format to paste.
  1467.  *  ppObj           LPUNKNOWN FAR * into which we store the object pointer.
  1468.  *
  1469.  * Return Value:
  1470.  *  HRESULT         NOERROR on success, error code otherwise.
  1471.  */
  1472.  
  1473. HRESULT CTenant::CreateStatic(LPDATAOBJECT pIDataObject, LPFORMATETC pFE
  1474.     , LPUNKNOWN FAR * ppObj)
  1475.     {
  1476.     HRESULT             hr;
  1477.     STGMEDIUM           stm;
  1478.     LPUNKNOWN           pIUnknown;
  1479.     LPOLECACHE          pIOleCache;
  1480.     LPPERSISTSTORAGE    pIPersistStorage;
  1481.     CLSID               clsID;
  1482.  
  1483.     *ppObj=NULL;
  1484.  
  1485.     //Try to get the data desired as specified in pFE->cfFormat
  1486.     hr=pIDataObject->GetData(pFE, &stm);
  1487.  
  1488.     if (FAILED(hr))
  1489.         return hr;
  1490.  
  1491.     //Create the object to handle this data.
  1492.     if (CF_METAFILEPICT==pFE->cfFormat)
  1493.         clsID=CLSID_FreeMetafile;
  1494.     else
  1495.         clsID=CLSID_FreeDib;
  1496.  
  1497.     hr=OleCreateDefaultHandler(clsID, NULL, IID_IUnknown
  1498.         , (LPVOID FAR *)&pIUnknown);
  1499.  
  1500.     if (FAILED(hr))
  1501.         {
  1502.         ReleaseStgMedium(&stm);
  1503.         return hr;
  1504.         }
  1505.  
  1506.     //Stuff the data into the object
  1507.     pIUnknown->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&pIPersistStorage);
  1508.     pIPersistStorage->InitNew(m_pIStorage);
  1509.  
  1510.     //Now that we have the cache object, shove the data into it.
  1511.     pIUnknown->QueryInterface(IID_IOleCache, (LPVOID FAR *)&pIOleCache);
  1512.     pIOleCache->Cache(pFE, ADVF_PRIMEFIRST, NULL);
  1513.  
  1514.     hr=pIOleCache->SetData(pFE, &stm, TRUE);
  1515.     pIOleCache->Release();
  1516.  
  1517.     //Insure there is a persistent copy on the disk; OleSave does it all for us
  1518.     OleSave(pIPersistStorage, m_pIStorage, TRUE);
  1519.     pIPersistStorage->Release();
  1520.  
  1521.     //The cache owns this now.
  1522.     ReleaseStgMedium(&stm);
  1523.  
  1524.     if (FAILED(hr))
  1525.         pIUnknown->Release();
  1526.     else
  1527.         *ppObj=pIUnknown;
  1528.  
  1529.     return hr;
  1530.     }
  1531.